﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bot.Domain.BotImport;
using Bot.Domain.Comm100OwnBot;
using Newtonsoft.Json;
using System.Threading;
using Bot.Domain.Bot;
using Bot.Domain;
using Bot.Domain;
using Bot.Domain.Entities;
using Bot.Domain.Interfaces;

namespace Bot.Domain
{
    public interface IComm100OwnBotApiService : IBotApiService
    {
    }

    public class Comm100OwnBotApiService : IComm100OwnBotApiService
    {
        private IComm100OwnBotService _comm100OwnBotService;
        private IIntentDomainService _intentDomainService;
        private IEntityDomainService _entityDomainService;
        private IEntityKeywordDomainService _entityKeywordDomainService;
        private ICategoryDomainService _categoryDomainService;
        private IIntentQuestionDomainService _intentQuestionDomainService;

        public Comm100OwnBotApiService(IComm100OwnBotService comm100OwnBotService,
            IIntentDomainService intentDomainService,
            IEntityDomainService entityDomainService,
            IEntityKeywordDomainService entityKeywordDomainService,
            ICategoryDomainService categoryDomainService,
            IIntentQuestionDomainService intentQuestionDomainService)
        {
            _comm100OwnBotService = comm100OwnBotService;
            _intentDomainService = intentDomainService;
            _entityDomainService = entityDomainService;
            _entityKeywordDomainService = entityKeywordDomainService;
            _categoryDomainService = categoryDomainService;
            _intentQuestionDomainService = intentQuestionDomainService;
        }

        public async Task<ApiResult> BatchDeleteEntities(BotDto bot, string[] MappingToBotEngines)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task<ApiResult> BatchDeleteIntents(BotDto bot, string[] MappingToBotEngines)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task BatchUpdateEntities(EntityDto[] entities, BotDto bot)
        {
            await Task.FromResult(0);
        }

        public async Task BatchUpdateIntents(IntentDto[] intents, BotDto bot)
        {
            await Task.FromResult(0);
        }

        public async Task<DetectIntentResponseDto> ChatWithBot(BotDto bot, QueryIntentParameter queryIntentParameter, string type = "question", string intentName = "")
        {
            DetectIntentResponseDto result = new DetectIntentResponseDto();

            QueryIntentData queryIntentData = new QueryIntentData {
                language=bot.Language,
                question= queryIntentParameter.question,
            };
            List<Comm100OwnBot.QueryIntentResponse> queryIntentResponses = await _comm100OwnBotService.QueryIntentAsync(bot.SiteId, bot.Id, queryIntentData, 10);
            if(queryIntentResponses!=null&& queryIntentResponses.Count > 0)
            {
                Comm100OwnBot.QueryIntentResponse maxQueryIntentResponse = queryIntentResponses.OrderByDescending(a => a.score).FirstOrDefault();
                result.intentDetectionConfidence = maxQueryIntentResponse.score;
                result.intentName = maxQueryIntentResponse.intent;
                result.allDetectIntents = queryIntentResponses;
                result.intent = new Newtonsoft.Json.Linq.JObject { };
            }

            return result;
        }

        public async Task<string> CreateBot(BotDto bot)
        {
            string id = "";

            id = Guid.NewGuid().ToString();
            await Task.FromResult(0);
            return id;
        }

        public async Task<string> CreateEntity(BotDto bot, EntityDto obj)
        {
            string id = "";

            id = Guid.NewGuid().ToString();
            await Task.FromResult(0);
            return id;
        }

        public async Task<string> CreateIntent(IntentDto intent, BotDto bot)
        {
            string id = "";

            id = Guid.NewGuid().ToString();
            await Task.FromResult(0);
            return id;
        }

        public async Task<bool> DeleteBot(BotDto bot)
        {
            bool bResult = true;

            await Task.FromResult(0);
            return bResult;
        }

        public async Task DeleteEntity(BotDto bot, EntityBasicDto obj)
        {
            await Task.FromResult(0);
        }

        public async Task DeleteIntent(BotDto bot, string MappingToBotEngine)
        {
            await Task.FromResult(0);
        }

        public async Task<string> EditEntity(BotDto bot, EntityDto obj)
        {
            string id = "";

            id = Guid.NewGuid().ToString();
            await Task.FromResult(0);
            return id;
        }

        public async Task<string> EditIntent(IntentDto intent, BotDto bot, string MappingToBotEngine)
        {
            string id = "";

            id = Guid.NewGuid().ToString();
            await Task.FromResult(0);
            return id;
        }

        public async Task<ApiResult> ExportBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task<ApiResult> GetBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task<List<EntityModelAggregate>> GetEntityList(BotDto bot)
        {
            List<EntityModelAggregate> entityModelAggregateList = new List<EntityModelAggregate>();

            string entityId = Guid.NewGuid().ToString();
            string entityName = "TestEntity1";
            entityModelAggregateList.Add(new EntityModelAggregate
            {
                EntityModel = new EntityModel
                {
                    Id = entityId,
                    EntityName = entityName,
                },
                EntityKeywordModelList = new List<EntityKeywordModel> {
                            new EntityKeywordModel{
                                EntityId=entityId,
                                EntityName=entityName,
                                Keyword="Testkeyword",
                                Synonyms=new List<string>{
                                    "TestSynoyms1",
                                    "TestSynoyms2",
                                },
                            }
                        },
            });
            await Task.FromResult(0);
            return entityModelAggregateList;
        }

        public async Task<List<IntentModelAggregate>> GetIntentList(BotDto bot)
        {
            List<IntentModelAggregate> intentModelAggregateList = new List<IntentModelAggregate>();

            List<IntentQuestionModel> intentQuestionModelList = new List<IntentQuestionModel>();

            string intentId = Guid.NewGuid().ToString();
            string intentName = "TestIntentName";

            intentQuestionModelList.Add(new IntentQuestionModel
            {
                Id = Guid.NewGuid().ToString(),
                Question = "TestQuestion",
                IntentId = intentId,
                IntentName = intentName,
            });

            intentModelAggregateList.Add(new IntentModelAggregate
            {
                IntentModel = new IntentModel
                {
                    Id = intentId,
                    IntentName = intentName,
                },
                IntentQuestionModelList = intentQuestionModelList,
            });
            await Task.FromResult(0);
            return intentModelAggregateList;
        }

        public async Task<ApiResult> GetOperations(BotDto bot, string operationName)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            QueryTrainStatusResponse response = await _comm100OwnBotService.QueryTrainStatusAsync(bot.SiteId, bot.Id, operationName);
            if (response.Status.ToLower().Equals("done"))
            {
                apiResult.IsSuccess = true;
                apiResult.Data = null;
            }
            else if (response.Status.ToLower().Equals("processing"))
            {
                apiResult.IsSuccess = true;
                apiResult.Data = operationName;
            }
            else
            {
                apiResult.IsSuccess = false;
                apiResult.Error = new ErrorInfo
                {
                    Message = response.ErrorMessage,
                };
            }

            Thread.Sleep(1000); //返回速度太快，重复请求速率太快

            return apiResult;
        }

        public async Task<ApiResult> ImportBot(BotDto bot, BotImportDataQueue botImportDataQueue)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };
            
            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task<ApiResult> RestoreBot(BotDto bot, BotImportDataQueue botImportDataQueue)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            apiResult.IsSuccess = true;
            apiResult.Data = null;
            await Task.FromResult(0);
            return apiResult;
        }

        public async Task<ApiResult> TrainBot(BotDto bot)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };

            Dictionary<string, object> config = new Dictionary<string, object> { };
            if (!string.IsNullOrEmpty(bot.WebhookTargetUrl))
            {
                config = JsonConvert.DeserializeObject<Dictionary<string, object>>(bot.WebhookTargetUrl);
            }

            List<Comm100OwnBot.Intent> intents = new List<Comm100OwnBot.Intent>();
            List<Category> categories = _categoryDomainService.GetByBotId(bot.Id);
            if (categories != null)
            {
                List<Entities.Intent> intentList = _intentDomainService.GetByCategoryIds(categories.Select(f => f.Id).ToList());
                if (intentList != null)
                {
                    var intentQuestions = _intentQuestionDomainService.GetByIntentIds(intentList.Select(f => f.Id).ToList());
                    foreach (IntentQuestion intentQuestion in intentQuestions)
                    {
                        Comm100OwnBot.Intent intent = intents.FirstOrDefault(a => a.id == intentQuestion.IntentId.ToString());
                        if (intent == null)
                        {
                            Entities.Intent intentFind = intentList.FirstOrDefault(f=>f.Id == intentQuestion.IntentId);
                            intent = new Comm100OwnBot.Intent
                            {
                                id = intentQuestion.IntentId.ToString(),
                                name = intentFind.Name,
                                questions = new List<string> { },
                            };
                            intents.Add(intent);
                        }

                        intent.questions.Add(intentQuestion.Content);
                    }
                }
            }            
           
            List<Comm100OwnBot.Entity> entities = new List<Comm100OwnBot.Entity>();
            var botEntityList = _entityDomainService.ListCustomEntities(bot.Id);
            if (botEntityList != null)
            {
                foreach (Entities.Entity botEntities in botEntityList)
                {
                    List<EntityKeyword> entityItemList = _entityKeywordDomainService.GetByEntityId(botEntities.Id);
                    List<string> keywords = new List<string>();
                    if (entityItemList != null)
                    {
                        foreach(var entityItem in entityItemList)
                        {
                            if (!string.IsNullOrWhiteSpace(entityItem.Content) && !keywords.Contains(entityItem.Content))
                            {
                                keywords.Add(entityItem.Content);
                            }
                            if (!string.IsNullOrWhiteSpace(entityItem.Synonyms))
                            {
                                var synonyms = JsonConvert.DeserializeObject<List<string>>(entityItem.Synonyms);
                                foreach(var synonym in synonyms)
                                {
                                    if (!string.IsNullOrWhiteSpace(synonym) && !keywords.Contains(synonym))
                                    {
                                        keywords.Add(synonym);
                                    }
                                }
                            }
                        }
                    }
                    entities.Add(new Comm100OwnBot.Entity
                    {
                        name = botEntities.Name,
                        entities = keywords,
                    });
                }
            }
            TrainingData trainingData = new TrainingData
            {
                config = config,
                language = bot.Language,
                intents = intents,
                entities= entities,
            };
            string trainId = await _comm100OwnBotService.TrainBotAsync(bot.SiteId, bot.Id, trainingData);
            apiResult.IsSuccess = true;
            apiResult.Data = trainId;

            return apiResult;
        }

        public async Task<ApiResult> IdentifyEntity(BotDto bot, QueryIntentParameter queryIntentParameter, List<QuestionEntity> intentQuestionEntities)
        {
            ApiResult apiResult = new ApiResult
            {
                IsSuccess = false
            };
            List<string> patterns = new List<string>();
            List<string> entity = new List<string>();
            if (intentQuestionEntities != null && intentQuestionEntities.Count > 0)
            {
                entity = intentQuestionEntities.Where(q => q.EntityType == 2).Select(q => q.DisplayName).Distinct().ToList();
                foreach (var item in intentQuestionEntities.Where(q => q.EntityType == 2 && q.DisplayName == "sys-any"))
                {
                    try
                    {
                        string before = "";
                        if (item.StartPos > 0)
                        {
                            before = item.Question.Substring(0, item.StartPos);
                        }
                        string after = "";
                        if (item.EndPos >= item.Question.Length - 1)
                        {
                            after = "";
                        }
                        else
                        {
                            after = item.Question.Substring(item.EndPos + 1);
                        }
                        patterns.Add(before + "#sys-any#" + after);
                    }
                    catch (Exception e)
                    {
                        LogHelper.WriteExceptionLog(e);
                    }
                }
            }
            QueryEntityData queryEntityData = new QueryEntityData
            {
                language = bot.Language,
                question = queryIntentParameter.question,
                entity = entity,
                pattern = patterns
            };
            
            Dictionary<string, List<string>> keyValues = await _comm100OwnBotService.IdentifyEntity(bot.SiteId, bot.Id, queryEntityData);
            apiResult.IsSuccess = true;
            apiResult.Data = keyValues;

            return apiResult;
        }
    }
}
